#ifndef WEBSOCKETPROXY_H
#define WEBSOCKETPROXY_H

#include <QObject>
#include <QMap>
#include <QTcpSocket>
#include <QTcpServer>

class QTcpServer;
class WebSocket;
class ClientSocket;

class WebSocketProxy : public QTcpServer
{
    Q_OBJECT
public:
    WebSocketProxy(QObject *parent = 0);

    void setDestination(const QString& hostname, int port);

    void listen(int port);

    bool hasPendingConnections() const;
    QTcpSocket *nextPendingConnection();

    void incomingConnection(qintptr descr);

public Q_SLOTS:
    void newWebConnected();
    void newClientConnected();

    void connectNewClient();
    void processClientError(QAbstractSocket::SocketError);
    void processWebError(QAbstractSocket::SocketError);

    void closeClient();
    void closeWeb();


    void dataReceivedFromWeb(QByteArray);
    void dataReceivedFromClient(QByteArray);

private:
    ClientSocket* removeLink(WebSocket* web);
    WebSocket* removeLink(ClientSocket* client);


private:
    //QTcpServer *p_server;

    int v_destinationPort;
    QString v_destinationHostname;

    QMap<ClientSocket*, WebSocket*> v_clientToWeb;
    QMap<WebSocket*, ClientSocket*> v_webToClient;

    QMap<ClientSocket *, WebSocket*> v_waitingClient;

    QList<int> v_pendingSocket;
};



class ClientSocket : public QTcpSocket
{
    Q_OBJECT
public:
    ClientSocket(QObject *parent = 0);

public Q_SLOTS:
    void processIncomingData();

Q_SIGNALS:
    void dataReceived(QByteArray);
};


class WebSocket : public QTcpSocket
{
    Q_OBJECT
private:
    struct Frame{
        char fin:1;
        char rsv1:1;
        char rsv2:1;
        char rsv3:1;
        char opcode:4;
        char mask:1;
        int length;
        char maskKey[4];
        int dataIndex;
    };

public:
    WebSocket(int socketDescriptor, QObject *parent = 0);

    void send(QByteArray data);
    /*void write(QByteArray data){ p_socket->write(data); }
    void close() { p_socket->close(); }*/

public Q_SLOTS:
    void processIncomingData();

private:
    static Frame computeFrame(QByteArray frame);
    static QString computeAcceptKey(QString key);

Q_SIGNALS:
    void handshakeSuccess();
    void onClosing();

    void dataReceived(QByteArray);

private:
    enum State{
        Handshake,
        Opened,
        Closed
    };



    QByteArray v_dataStream;

    State v_state;



    //QTcpSocket *p_socket;

};

#endif // WEBSOCKETPROXY_H
